import { CanvasContext } from "./designType";
import { Point } from "./Point";

export interface DrawStrategy {
  drawStroke(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    color: string,
    lineWidth?: number,
    isDashed?: boolean
  ): void;

  drawFill(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    fillColor: string
  ): void;

  draw(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    strokeColor: string,
    fillColor?: string,
    lineWidth?: number,
    isDashed?: boolean
  ): void;
  getPoints(): Point; // 新增方法，返回当前策略的 points
}

export class RectDrawStrategy implements DrawStrategy {
  private points: Point[] = [];
  drawStroke(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    color: string,
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (points.length < 2) {
      console.error("RectDrawStrategy requires exactly 2 points.");
      return;
    }
    this.points = points;
   
    const path = canvas.createPath2D();
    path.moveTo(points[0].x, points[0].y);
    path.lineTo(points[1].x, points[0].y);
    path.lineTo(points[1].x, points[1].y);
    path.lineTo(points[0].x, points[1].y);
    path.closePath();

    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(isDashed ? [10, 5] : []);
    ctx.stroke(path);
  }

  drawFill(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    fillColor: string
  ): void {
    if (points.length < 2) return;
    this.points = points;

    const path = canvas.createPath2D();
    path.moveTo(points[0].x, points[0].y);
    points.slice(1).forEach(point => path.lineTo(point.x, point.y));
    path.closePath();

    ctx.fillStyle = fillColor;
    ctx.fill(path);
  }

  draw(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    strokeColor: string,
    fillColor: string = "",
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (fillColor) this.drawFill(ctx, canvas, points, fillColor);
    this.drawStroke(ctx, canvas, points, strokeColor, lineWidth, isDashed);
  }

  getPoints(): Point {
    if (this.points.length < 2) {
      throw new Error("必须有两个点来表示矩形的左上角和右下角");
    }
  
    // 获取两个点的坐标
    const x1 = this.points[0].x;
    const y1 = this.points[0].y;
    const x2 = this.points[1].x;
    const y2 = this.points[1].y;
  
    // 计算左上角和右下角的坐标
    const topLeftX = Math.min(x1, x2);
    const topLeftY = Math.min(y1, y2);
    const bottomRightX = Math.max(x1, x2);
    const bottomRightY = Math.max(y1, y2);
  
    // 创建并返回一个矩形的 Point 实例
    const rectPoint = new Point(
      topLeftX,
      topLeftY,
      "rect",
      {
        width: bottomRightX - topLeftX,  // 矩形的宽度
        height: bottomRightY - topLeftY  // 矩形的高度
      }
    );
  
    return rectPoint;
  }
}

export class LineDrawStrategy implements DrawStrategy {
  private points: Point[] = [];
  drawStroke(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    color: string,
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (points.length < 2) {
      console.error("LineDrawStrategy requires at least 2 points.");
      return;
    }

    const path = canvas.createPath2D();
    this.points = points;
    path.moveTo(points[0].x, points[0].y);
    path.lineTo(points[1].x, points[1].y);

    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(isDashed ? [10, 5] : []);
    ctx.stroke(path);
  }

  drawFill(ctx: CanvasContext, canvas: WechatMiniprogram.Canvas, points: Point[], fillColor: string): void {
    // Line does not require fill
  }

  draw(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    strokeColor: string,
    fillColor: string = "",
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    this.drawStroke(ctx, canvas, points, strokeColor, lineWidth, isDashed);
  }

  getPoints():Point {
    return new Point(this.points[0].x, this.points[0].y,
      "line",
      {
      end: { x: this.points[1].x, y: this.points[1].y }
      }
    );
  }
}

export class ArcDrawStrategy implements DrawStrategy {
  private points: Point[] = [];
  drawStroke(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    color: string,
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (points.length < 2) {
      console.error("ArcDrawStrategy requires at least 2 points (center and radius point).");
      return;
    }
    this.points = points;

    const center = points[0];
    const radiusPoint = points[1];
    const radius = Math.sqrt((radiusPoint.x - center.x) ** 2 + (radiusPoint.y - center.y) ** 2);

    const path = canvas.createPath2D();
    path.arc(center.x, center.y, radius, 0, Math.PI * 2);

    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(isDashed ? [10, 5] : []);
    ctx.stroke(path);
  }

  drawFill(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    fillColor: string
  ): void {
    if (points.length < 2) return;
    this.points = points;

    const center = points[0];
    const radiusPoint = points[1];
    const radius = Math.sqrt((radiusPoint.x - center.x) ** 2 + (radiusPoint.y - center.y) ** 2);

    const path = canvas.createPath2D();
    path.arc(center.x, center.y, radius, 0, Math.PI * 2);

    ctx.fillStyle = fillColor;
    ctx.fill(path);
  }

  draw(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    strokeColor: string,
    fillColor: string = "",
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (fillColor) this.drawFill(ctx, canvas, points, fillColor);
    this.drawStroke(ctx, canvas, points, strokeColor, lineWidth, isDashed);
  }

  getPoints() {
    return this.points[0];
  }
}

export class PolygonDrawStrategy implements DrawStrategy {
  private points: Point[] = [];
  drawStroke(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    color: string,
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (points.length < 3) {
      console.error("PolygonDrawStrategy requires at least 3 points.");
      return;
    }
    this.points = points;

    const path = canvas.createPath2D();
    path.moveTo(points[0].x, points[0].y);
    points.slice(1).forEach(point => path.lineTo(point.x, point.y));
    path.closePath();

    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(isDashed ? [10, 5] : []);
    ctx.stroke(path);
  }

  drawFill(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    fillColor: string
  ): void {
    if (points.length < 3) return;
    this.points = points;

    const path = canvas.createPath2D();
    path.moveTo(points[0].x, points[0].y);
    points.slice(1).forEach(point => path.lineTo(point.x, point.y));
    path.closePath();

    ctx.fillStyle = fillColor;
    ctx.fill(path);
  }

  draw(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    strokeColor: string,
    fillColor: string = "",
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (fillColor) this.drawFill(ctx, canvas, points, fillColor);
    this.drawStroke(ctx, canvas, points, strokeColor, lineWidth, isDashed);
  }

  getPoints() {
    return this.points[0];
  }
}


export class HorizontalLineDrawStrategy implements DrawStrategy {
  private points: Point[] = [];
  drawStroke(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    color: string,
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (points.length < 2) {
      console.error("LineDrawStrategy requires at least 2 points.");
      return;
    }
    this.points = points;

    const path = canvas.createPath2D();
    path.moveTo(points[0].x, points[0].y);
    path.lineTo(points[1].x, points[0].y);

    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(isDashed ? [10, 5] : []);
    ctx.stroke(path);
  }

  drawFill(ctx: CanvasContext, canvas: WechatMiniprogram.Canvas, points: Point[], fillColor: string): void {
    // Line does not require fill
  }

  draw(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    strokeColor: string,
    fillColor: string = "",
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    this.drawStroke(ctx, canvas, points, strokeColor, lineWidth, isDashed);
  }

  getPoints() {
    return this.points[0];
  }
}

export class VerticalLineDrawStrategy implements DrawStrategy {
  private points: Point[] = [];
  drawStroke(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    color: string,
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    if (points.length < 2) {
      console.error("LineDrawStrategy requires at least 2 points.");
      return;
    }
    this.points = points;

    const path = canvas.createPath2D();
    path.moveTo(points[0].x, points[0].y);
    path.lineTo(points[0].x, points[1].y);

    ctx.strokeStyle = color;
    ctx.lineWidth = lineWidth;
    ctx.setLineDash(isDashed ? [10, 5] : []);
    ctx.stroke(path);
  }

  drawFill(ctx: CanvasContext, canvas: WechatMiniprogram.Canvas, points: Point[], fillColor: string): void {
    // Line does not require fill
  }

  draw(
    ctx: CanvasContext,
    canvas: WechatMiniprogram.Canvas,
    points: Point[],
    strokeColor: string,
    fillColor: string = "",
    lineWidth: number = 1,
    isDashed: boolean = false
  ): void {
    this.drawStroke(ctx, canvas, points, strokeColor, lineWidth, isDashed);
  }

  getPoints(): Point {
    return this.points[0];
  }
}